﻿Imports System.Linq
Namespace UI.Windows.ViewModels
	Public Class ArchiveModel
		Inherits ViewBase



		''' <summary>
		''' Performs prep for the archive view model.
		''' </summary>
		''' <remarks></remarks>
		Public Sub New()
			'IsArchive = My.Application.Show.ShowFile.IsArchive
		End Sub

		''' <summary>
		''' Gets/Sets the Details property, which contains information about the current archiving activity.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Property Details As String
			Get
				Return DetailsProperty
			End Get
			Set(value As String)
				SetProp(DetailsProperty, value)
			End Set
		End Property
		Private DetailsProperty As String = ""

		''' <summary>
		''' Gets/Sets whether the current show file is already an archive.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Property HasUnusedFiles As Boolean
			Get
				Return HasUnusedFilesProperty
			End Get
			Set(value As Boolean)
				SetProp(HasUnusedFilesProperty, value)
			End Set
		End Property
		Private HasUnusedFilesProperty As Boolean = False

		''' <summary>
		''' Gets/Sets the FilePath property, which is the path and folder the archive will be saved to.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Property FilePath As String
			Get
				Return FilePathProperty
			End Get
			Set(value As String)
				SetProp(FilePathProperty, value)
				RaisePropertyChanged("FullPath")
			End Set
		End Property
		Private FilePathProperty As String = GetDefaultFilePath()

		''' <summary>
		''' Gets the default file name to use for the archive.
		''' </summary>
		''' <returns></returns>
		''' <remarks></remarks>
		Private Function GetDefaultFilePath() As String
			If My.Application.Show.ShowFile.Path <> "" Then
				Return My.Application.Show.ShowFile.Path '& My.Application.Show.ShowFile.Name.Replace("q2q", "qArchive")
			Else
				Return My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\Q2Cue Show Files\"	'& My.Application.Show.ShowFile.Name & ".qArchive"
			End If
		End Function

		''' <summary>
		''' Gets/Sets the FileName property, which is the path and folder the archive will be saved to.
		''' Defaults to the path of the show file, with a folder appended named the ShowFile name with .qArchive appended.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Property FileName As String
			Get
				Return FileNameProperty
			End Get
			Set(value As String)
				SetProp(FileNameProperty, value)
				RaisePropertyChanged("FullPath")
			End Set
		End Property
		Private FileNameProperty As String = GetDefaultFileName()

		''' <summary>
		''' Returns the file path and file name for presentation purposes.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public ReadOnly Property FullPath As String
			Get
				Return FilePath & "\" & FileName
			End Get
		End Property

		''' <summary>
		''' Gets the default file name to use for the archive.
		''' </summary>
		''' <returns></returns>
		''' <remarks></remarks>
		Private Function GetDefaultFileName() As String
			Return My.Application.Show.ShowFile.Name.Replace(".q2q", ".q2qx")
		End Function

		''' <summary>
		''' Gets/Sets the list of missing files encountered while archiving.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Property MissingFileList As List(Of String)
			Get
				Return MissingFileListProperty
			End Get
			Set(value As List(Of String))
				SetProp(MissingFileListProperty, value)
			End Set
		End Property
		Private MissingFileListProperty As List(Of String) = New List(Of String)


		''' <summary>
		''' Gets/Sets the list of unused files encountered while archiving.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Property UnusedFileList As List(Of String)
			Get
				Return UnusedFileListProperty
			End Get
			Set(value As List(Of String))
				SetProp(UnusedFileListProperty, value)
			End Set
		End Property
		Private UnusedFileListProperty As List(Of String) = New List(Of String)

		''' <summary>
		''' Gets/Sets whether to delete unused audio files from the project archive.
		''' </summary>
		''' <value></value>
		''' <returns></returns>
		''' <remarks></remarks>
		Public Property DeleteUnusedAudioFiles As Boolean
			Get
				Return DeleteUnusedAudioFilesProperty
			End Get
			Set(value As Boolean)
				SetProp(DeleteUnusedAudioFilesProperty, value)
			End Set
		End Property
		Private DeleteUnusedAudioFilesProperty As Boolean = False


		''' <summary>
		''' Add a file to the missing file list.
		''' </summary>
		''' <param name="MissingFile">The name of the missing file (should include the entire path).</param>
		''' <remarks></remarks>
		Public Sub AddMissingFile(MissingFile As String)
			MissingFileList.Add(MissingFile)
			RaisePropertyChanged("MissingFileList")
			'If MissingFileList.Count > 0 Then
			'	HasUnusedFiles = True
			'Else
			'	HasUnusedFiles = False
			'End If
		End Sub

		''' <summary>
		''' Remove a file from the missing file list.
		''' </summary>
		''' <param name="MissingFile">The name of the missing file (should include the entire path).</param>
		''' <remarks></remarks>
		Public Sub RemoveMissingFile(MissingFile As String)
			MissingFileList.Remove(MissingFile)
			RaisePropertyChanged("MissingFileList")
			'If MissingFileList.Count > 0 Then
			'	HasUnusedFiles = True
			'Else
			'	HasUnusedFiles = False
			'End If
		End Sub

		''' <summary>
		''' Add a file to the Unused file list.
		''' </summary>
		''' <param name="UnusedFile">The name of the Unused file (should include the entire path).</param>
		''' <remarks></remarks>
		Public Sub AddUnusedFile(UnusedFile As String)
			UnusedFileList.Add(UnusedFile)
			RaisePropertyChanged("UnusedFileList")
			If UnusedFileList.Count > 0 Then
				HasUnusedFiles = True
			Else
				HasUnusedFiles = False
			End If
		End Sub

		''' <summary>
		''' Remove a file from the Unused file list.
		''' </summary>
		''' <param name="UnusedFile">The name of the Unused file (should include the entire path).</param>
		''' <remarks></remarks>
		Public Sub RemoveUnusedFile(UnusedFile As String)
			UnusedFileList.Remove(UnusedFile)
			RaisePropertyChanged("UnusedFileList")
			If UnusedFileList.Count > 0 Then
				HasUnusedFiles = True
			Else
				HasUnusedFiles = False
			End If
		End Sub


		''' <summary>
		''' Run the commands to create the archive.
		''' </summary>
		''' <remarks></remarks>
		Public Sub CreateOrUpdateArchive()
			Try
				UnusedFileList = New List(Of String)
				MissingFileList = New List(Of String)
				HasUnusedFiles = False
				Using pack As System.IO.Packaging.ZipPackage = System.IO.Packaging.ZipPackage.Open(FullPath, IO.FileMode.OpenOrCreate)

					If pack.GetParts.Count > 0 Then
						Dim ShowFileList = pack.GetParts().Where(Function(part) part.Uri.OriginalString.StartsWith("/ShowFile")).ToList
						For Each p In ShowFileList
							pack.DeletePart(p.Uri)
							CreateShowFilePart(pack)
							AddDetail("Updated show file in archive.")
						Next
						Dim AudioPartList = pack.GetParts().Where(Function(part) part.Uri.OriginalString.StartsWith("/AudioFiles")).ToList
						For Each p In AudioPartList
							If DeleteUnusedAudioFiles Then
								Dim result = (From i In My.Application.Show.ShowFile.CueList.Where(Function(c) c.GetType Is GetType(Cues.Audio)) Where CType(i, Cues.Audio).FileName = Uri.UnescapeDataString(p.Uri.OriginalString).Remove(0, 12).Replace("/", "\")).Count
								If result < 1 Then
									AddDetail("Removed unused audio file from project: " & p.Uri.ToString)
									pack.DeletePart(p.Uri)
								End If
							ElseIf Not DeleteUnusedAudioFiles Then
								Dim temp As String = Uri.UnescapeDataString(p.Uri.OriginalString)
								Dim temp2 As String = temp.Remove(0, 12)
								Dim temp3 As String = temp2.Replace("/", "\")
								Dim result = (From i In My.Application.Show.ShowFile.CueList.Where(Function(c) c.GetType Is GetType(Cues.Audio)) Where CType(i, Cues.Audio).FileName = temp3).Count
								If result < 1 Then
									AddUnusedFile(temp3)
								End If
							End If
						Next
					Else
						CreateShowFilePart(pack)
						AddDetail("Placed show file in cue archive.")
					End If
					For Each a As Cues.Audio In My.Application.Show.ShowFile.CueList.Where(Function(c) c.GetType Is GetType(Cues.Audio))
						If pack.GetParts.Where(Function(p)
												   Dim temp As String = Uri.UnescapeDataString(p.Uri.OriginalString).Replace("/", "\")
												   Return temp.Contains(a.FileName)
											   End Function).Count < 1 Then
							CreateAudioFilePart(pack, a.FileName)
							AddDetail("Placed audio file: " & a.FileName & " in cue archive.")
						End If
					Next

					AddDetail("Completed creating or updating the cue archive.")

				End Using

			Catch ex As Exception
				AddDetail("ERROR: Couldn't create the cue archive. Please try again!" & vbCrLf & "---" & vbCrLf & ex.Message)
				MsgBox("ERROR: Couldn't create the cue archive. Please try again!", MsgBoxStyle.Critical)
				If System.IO.File.Exists(FullPath) AndAlso FileIO.FileSystem.GetFileInfo(FullPath).Length = 0 Then
					System.IO.File.Delete(FullPath)
				End If
			End Try
		End Sub

		Public Function CreateShowFilePart(pack As System.IO.Packaging.ZipPackage) As System.IO.Packaging.ZipPackagePart
			Dim p As System.IO.Packaging.ZipPackagePart = pack.CreatePart(System.IO.Packaging.PackUriHelper.CreatePartUri(New Uri("ShowFile\" & My.Application.Show.ShowFile.Name, UriKind.Relative)), System.Net.Mime.MediaTypeNames.Application.Octet)
			CopyStream(New System.IO.StreamReader(My.Application.Show.ShowFile.Path & "/" & My.Application.Show.ShowFile.Name).BaseStream, p.GetStream)
			Return p
		End Function

		Private Function CreateAudioFilePart(pack As System.IO.Packaging.ZipPackage, FilePath As String) As System.IO.Packaging.ZipPackagePart
			Dim p As System.IO.Packaging.ZipPackagePart = pack.CreatePart(System.IO.Packaging.PackUriHelper.CreatePartUri(New Uri("AudioFiles\" & FilePath, UriKind.Relative)), System.Net.Mime.MediaTypeNames.Application.Octet)
			CopyStream(New System.IO.StreamReader(FilePath).BaseStream, p.GetStream)
			Return p
		End Function

		Public Shared Sub CopyStream(Source As System.IO.Stream, Target As System.IO.Stream)
			Dim bufSize As Integer = &H1000
			Dim buf As Byte() = New Byte(bufSize - 1) {}
			Dim bytesRead As Integer = 0
			While (InlineAssignHelper(bytesRead, Source.Read(buf, 0, bufSize))) > 0
				Target.Write(buf, 0, bytesRead)
			End While
		End Sub

		Public Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
			target = value
			Return value
		End Function

		Private Sub AddDetail(msg As String)
			Details += Date.Now.ToShortTimeString & " | " & msg & vbCrLf
		End Sub

	End Class
End Namespace